using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Perfecter_Grapple : MonoBehaviour
{
    [Header("脚本引用:")]
    public Grappling_Rope grappleRope;

    [Header("层设置:")]
    [SerializeField] private bool grappleToAll = false;
    [SerializeField] private int grappableLayerNumber = 9;

    [Header("主摄像机:")]
    public Camera m_camera;

    [Header("变换引用:")]
    public Transform gunHolder;
    public Transform gunPivot;
    public Transform firePoint;

    [Header("物理引用:")]
    public SpringJoint2D m_springJoint2D;
    public Rigidbody2D m_rigidbody;

    [Header("旋转:")]
    [SerializeField] private bool rotateOverTime = true;
    [Range(0, 60)] [SerializeField] private float rotationSpeed = 4;

    [Header("距离:")]
    [SerializeField] private bool hasMaxDistance = false;
    [SerializeField] private float maxDistnace = 20;

    private enum LaunchType //发射类型
    {
        Transform_Launch,
        Physics_Launch
    }

    [Header("发射:")]
    [SerializeField] private bool launchToPoint = true;
    [SerializeField] private LaunchType launchType = LaunchType.Physics_Launch;
    [SerializeField] private float launchSpeed = 1;

    [Header("无发射点")]
    [SerializeField] private bool autoConfigureDistance = false;
    [SerializeField] private float targetDistance = 3;
    [SerializeField] private float targetFrequncy = 1;

    [HideInInspector] public Vector2 grapplePoint;
    [HideInInspector] public Vector2 grappleDistanceVector;

    private void Start() //开始
    {
        grappleRope.enabled = false;
        m_springJoint2D.enabled = false;
         
    }

    private void Update() //更新函数，控制输入
    {
        if (Input.GetKeyDown(KeyCode.Mouse0)) //通过Input的顺序设定函数的执行顺序，先进行钩爪选取点的定位
        {
            SetGrapplePoint();          
        }
        else if (Input.GetKey(KeyCode.Mouse0)) //从上一步的定位中把grapplerope启用
        {
            if (grappleRope.enabled)
            {
                RotateGun(grapplePoint, false); //进行钩锁枪的旋转
            }
            else
            {
                Vector2 mousePos = m_camera.ScreenToWorldPoint(Input.mousePosition);
                RotateGun(mousePos, true);
            }
                    
            if (launchToPoint && grappleRope.isGrappling) //如果选择点对点发射且正在钩中目标
            {
                if (launchType == LaunchType.Transform_Launch) //如果发射类型是使用Transform类型发射
                {
                    Vector2 firePointDistnace = firePoint.position - gunHolder.localPosition;
                    Vector2 targetPos = grapplePoint - firePointDistnace;
                    gunHolder.position = Vector2.Lerp(gunHolder.position, targetPos, Time.deltaTime * launchSpeed); //采用插值的形式，模拟绳索命中的物理效果
                }
            }
        }
        else if (Input.GetKeyUp(KeyCode.Mouse0)) //若抬起左键，则将一切启用的相关布尔置否，恢复原状
        {
            grappleRope.enabled = false;
            m_springJoint2D.enabled = false;
            m_rigidbody.gravityScale = 1;
        }
        else //时刻获取鼠标的屏幕信息位置
        {
            Vector2 mousePos = m_camera.ScreenToWorldPoint(Input.mousePosition);
            RotateGun(mousePos, true);
        }
    }

    void RotateGun(Vector3 lookPoint, bool allowRotationOverTime) //实现绳索枪根据鼠标进行旋转功能
    {
        Vector3 distanceVector = lookPoint - gunPivot.position; //定义三维距离向量=朝向点-枪锚点位置

        float angle = Mathf.Atan2(distanceVector.y, distanceVector.x) * Mathf.Rad2Deg; //定义一个角度，其值等于距离向量tan所对应的弧度值*弧度值转化为角度值的常量


        if (rotateOverTime && allowRotationOverTime) //当采用根据时间延迟旋转时，采用四元数的插值旋转，在原本的旋转角和获得的绕轴的新角度中进行随时间
        {
            gunPivot.rotation = Quaternion.Lerp(gunPivot.rotation, Quaternion.AngleAxis(angle, Vector3.forward), Time.deltaTime * rotationSpeed);
        }
        else
        {
            gunPivot.rotation = Quaternion.AngleAxis(angle, Vector3.forward); //不采用时间插值变化时时，直接让强旋转角角度等于计算出的角度绕轴的四元数即可
        }
    }

    void SetGrapplePoint() //设定钩取点(主要是位置的计算和注意某些添加的限定条件)
    {
        Vector2 distanceVector = m_camera.ScreenToWorldPoint(Input.mousePosition) - gunPivot.position; //设置一个二维向量distance用于记录鼠标点击的点和枪锚点之间的距离
        if (Physics2D.Raycast(firePoint.position, distanceVector.normalized)) //发射一条射线，起始点为开火点，方向为distance的方向向量
        {
            RaycastHit2D _hit = Physics2D.Raycast(firePoint.position, distanceVector.normalized); //保存刚才的射线为hit
            if (_hit.transform.gameObject.layer == grappableLayerNumber || grappleToAll) //选择是否选中任意的可抓取图层或是某一指定图层
            {
                if (Vector2.Distance(_hit.point, firePoint.position) <= maxDistnace || !hasMaxDistance) //当命中点和开火电站之间的距离小于最大距离或者不限定最大距离时
                {
                    grapplePoint = _hit.point; //将命中点位置赋予抓取点位置
                    grappleDistanceVector = grapplePoint - (Vector2)gunPivot.position; //抓钩的距离向量等于钩锁点减去钩锁枪的锚点位置
                    grappleRope.enabled = true; //打开绳索变量
                }
            }
        }
    }

    public void Grapple() //钩锁执行(真正决定移动)                              
    {
        m_springJoint2D.autoConfigureDistance = false; //设定弹簧关节组建的自动计算距离属性为假
        if (!launchToPoint && !autoConfigureDistance) //当对点发射和自动计算距离均为假时，将目标距离和目标频率赋给弹簧组件的属性
        {
            m_springJoint2D.distance = targetDistance;
            m_springJoint2D.frequency = targetFrequncy;
        }
        if (!launchToPoint) //如果仅为不对点发射
        {
            if (autoConfigureDistance) //若自动计算距离
            {
                m_springJoint2D.autoConfigureDistance = true;
                m_springJoint2D.frequency = 0; //弹簧组件频率属性为0，该值越大，弹簧越硬
            }

            m_springJoint2D.connectedAnchor = grapplePoint; //不自动计算距离且不对点发射时
            m_springJoint2D.enabled = true;
        }
        else //对点发射时，选择发射类型，有物理类发射和Transform类发射
        {
            switch (launchType)
            {
                case LaunchType.Physics_Launch:
                    m_springJoint2D.connectedAnchor = grapplePoint; //当使用物理发射时，将钩取点赋予弹簧的连接锚点

                    Vector2 distanceVector = firePoint.position - gunHolder.position; //长度变量等于开火点距离减去持枪距离

                    m_springJoint2D.distance = distanceVector.magnitude; //将长度变量赋给弹簧组建的距离属性，保证钩爪拉到尽头时有一定的距离
                    m_springJoint2D.frequency = launchSpeed; //弹簧频率（强度）等于发射速度
                    m_springJoint2D.enabled = true; //打开弹簧组件，进行拉伸
                    break;
                case LaunchType.Transform_Launch:
                    m_rigidbody.gravityScale = 0; //当使用Transform发射时，将物体的重力设置为0
                    m_rigidbody.velocity = Vector2.zero; //启动钩爪时，将物体速度清零
                    break;
            }
        }
    }

    private void OnDrawGizmosSelected() //始终在场景中绘制可视的Gizmo,On方法
    {
        if (firePoint != null && hasMaxDistance)
        {
            Gizmos.color = Color.green;
            Gizmos.DrawWireSphere(firePoint.position, maxDistnace);
        }
    }

}
